<?php

namespace nabu\libs\csrf;

defined('NABU') || exit;

// Genera y valida tokens contra ataques CSRF.
class csrf {
  private const hash_size     = 32;
  private const function_hash = 'sha256';
  private const secret        = 'SvX-GfWl_iTkaI6c-ql5';
  private const expiration    = 4; // Horas.

  // Elimina la variable de sesión.
  private static function destroy_token() {
    unset($_SESSION['csrf']);
  }

  private static function errors(string $error) {
    self::destroy_token();

    $GLOBALS['messages'] -> errors($error, 400);
  }

  // Genera un token en base a bytes aleatorios.
  public static function generate_token() {
    $key = bin2hex(random_bytes(self::hash_size));

    $_SESSION['csrf'] = array(
      'token'      => hash_hmac(self::function_hash, self::secret, $key),
      'expiration' => time() + (60 * 60 * self::expiration)
    );

    return $_SESSION['csrf']['token'];
  }

  // Valida si un token no está expirado y es igual al generado.
  public static function validate_token($token2) {
    if (empty($_SESSION['csrf']) || !is_array($_SESSION['csrf']))
      self::errors('Token inválido');

    if (empty($_SESSION['csrf']['token']) || empty($_SESSION['csrf']['expiration']))
      self::errors('No se encontró un token en el formulario');

    $expiration = $_SESSION['csrf']['expiration'];

    if (time() > $expiration)
      self::errors('El formulario ha expirado, por favor recargue la página web');

    if (!hash_equals($_SESSION['csrf']['token'], $token2))
      self::errors('Los tokens no coinciden');

    self::destroy_token();
  }
}
